module i2c_control(
	clk				,
	rst_n				,
	wrreq				,
	rdreq				,
	addr				,
	addr_mode		,
	wrdata			,
	device_id		,
	rddata			,
	rw_done			,
	ack				,
	i2c_sclk			,
	i2c_sdat
);

	input						clk			;							
	input						rst_n			;		
	input						wrreq			;			
	input						rdreq			;			
	input				[15:0]addr			;			
	input						addr_mode	;		
	input				[7:0]	wrdata		;			
	input				[7:0]	device_id	;	
	output	reg	[7:0]	rddata		;			
	output   reg			rw_done		;		
	output   reg			ack			;		
	output   				i2c_sclk		;	
	inout						i2c_sdat		;
	
	localparam	IDLE				=	8'b00000001,					
					WR_REG			=	8'b00000010,	
					WAIT_WR_DONE	=	8'b00000100,	
					WR_REG_DONE		=	8'b00001000,	
					RD_REG			=	8'b00010000,	
					WAIT_RD_DONE	=	8'b00100000,	
					RD_REG_DONE		=	8'b01000000,
					WAIT_DLY 		=	8'b10000000;
					
	localparam	WR				=	6'b000001 ,	//写请求		
					STA			=	6'b000010 , //起始位请求
					RD				=	6'b000100 , //读请求
					STO			=	6'b001000 , //停止位请求
					ACK			=	6'b010000 ,	//应答为请求
					NACK			=	6'b100000 ; //无应答位请求
					
	reg 	[5:0] 	cmd;
	reg 				go;
	reg 	[7:0] 	tx_data;
	reg	[7:0]		state;
	reg 	[7:0]		cnt;
	reg   [31:0]   dly_cnt;
	wire 	[7:0] 	rx_data;
	wire		 		ack_o;
	wire 				trans_done;
	wire  [15:0] 	reg_addr;
	
	assign reg_addr = addr_mode ? addr : {addr[7:0],addr[15:8]};
	
	always @ (posedge clk or negedge rst_n)
	if (!rst_n)
		begin
			state <= IDLE;
			rddata <= 8'd0;
			rw_done <= 1'b0;
			ack <= 1'b0;
			cnt <= 8'd0;
			cmd <= 6'd0;
			tx_data <= 8'd0;
			go <= 1'b0;
			dly_cnt <= 32'd0;
		end
	else 
		begin
			case (state)
				IDLE			:	begin
										cnt <= 8'd0;
										ack <= 1'b0;
										rw_done <= 1'b0;
										dly_cnt <= 0;
										if (wrreq)
											state <= WR_REG;
										else if (rdreq)
											state <= RD_REG;
										else
											state <= IDLE;
									end
									
				WR_REG		 :	begin
										state <= WAIT_WR_DONE;
										case (cnt)
											0	:	write_byte(WR | STA , device_id);	
											1	:	write_byte(WR , reg_addr[15:8]);
											2	:	write_byte(WR , reg_addr[7:0]);	
											3	:	write_byte(WR | STO ,wrdata);
											default :;
										endcase
									end
									
				WAIT_WR_DONE :	begin
										go <= 1'b0;
										if (trans_done)
											begin
												ack <= ack | ack_o;
												case (cnt)
													0	:	begin cnt <= 1 ; state <= WR_REG;end
													1	:	begin state <= WR_REG; if (addr_mode) cnt <= 2; else cnt <= 3;  end
													2	:	begin cnt <= 3; state <= WR_REG; end
													3	:	begin state <= WR_REG_DONE; end				
													default:state <= IDLE;
												endcase
											end
									end
									
				WR_REG_DONE	 :	begin
										state <= IDLE;
										rw_done <= 1'b1;
									end
									

				RD_REG		 :	begin
										state <= WAIT_RD_DONE;
										case (cnt)
											0	:	write_byte(WR | STA , device_id);	
											1	:	write_byte(WR , reg_addr[15:8]);
											2	:	write_byte(WR , reg_addr[7:0]);	
											3	:	write_byte(WR | STA , device_id | 1);
											4	:	read_byte(RD | ACK | STO);
											default :;
										endcase
									end
									
				WAIT_RD_DONE :	begin
										go <= 1'b0;
										if (trans_done)
											begin
												if (cnt <= 3)
													ack <= ack | ack_o;
												case (cnt)
													0	:	begin cnt <= 1 ; state <= RD_REG;end
													1	:	begin state <= RD_REG; if (addr_mode) cnt <= 2; else cnt <= 3;  end
													2	:	begin cnt <= 3; state <= RD_REG; end
													3	:	begin cnt <= 4; state <= RD_REG; end
													4	:	begin state <= RD_REG_DONE;  end
													default:state <= IDLE;
												endcase
											end
									end
					
						
				RD_REG_DONE	:	begin
										state <= IDLE;
										rddata <= rx_data;
										rw_done <= 1'b1;
									end
									
				default : state <= IDLE;
			endcase
		end
	
	i2c_bit_shift	i2c_bit_shift_inst(
		.clk				(clk			),	//系统时钟	
		.rst_n			(rst_n		),	//系统复位
		.cmd				(cmd			),	//控制总线实现各种传输操作的各种命令的组合
		.tx_data			(tx_data		),	//总线要发送的8位数据，需要传输的数据经此端口传入该模块
		.go				(go			),	//整个模块的启动使能信号
		.ack_o			(ack_o		),	//从机是否应答标志
		.rx_data			(rx_data		),	//总线收到的8位数据，读操作时读到的数据由此端口输出
		.i2c_sclk		(i2c_sclk	),	//i2c时钟总线
		.i2c_sdat		(i2c_sdat	),	//i2c数据总线
		.trans_done		(trans_done)	 	//发送或接收8位数据完成标志信号
	);	
	
	
	task read_byte;
	input [5:0] ctrl_cmd;
		begin
			cmd <= ctrl_cmd;
			go <= 1'b1;
		end
	endtask
	
	task write_byte;
	input [5:0] ctrl_cmd;
	input [7:0] wr_byte_data;
		begin
			cmd <= ctrl_cmd;
			go <= 1'b1;
			tx_data <= wr_byte_data;
		end
	endtask


endmodule 